package com.yzd.learnjava.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import com.yzd.learnjava.util.Print;

public class SemaphoreDemo {
	final static int SIZE = 25 ;
	public static void main(String[] args) throws InterruptedException {
		final Pool<Fat> pool = new Pool<Fat>(Fat.class, SIZE);
		ExecutorService exec = Executors.newCachedThreadPool();
		for(int i = 0 ; i < SIZE; i++) {
			exec.execute(new CheckoutTask<Fat>(pool));
		}
		Print.print("All CheckoutTasks created");
		List<Fat> list = new ArrayList<Fat>();
		for(int i = 0 ; i < SIZE; i++) {
			Fat f = pool.checkOut();
			Print.printnb(i + ": main() thread checked out");
			f.operation();
			list.add(f);
		}
		
		Future<?> blocked = exec.submit(new Runnable() {
			public void run() {
				try {
					pool.checkOut();
				} catch (InterruptedException e) {
					Print.print("Checkout() interrupted");
				}
			}
		});
		
		TimeUnit.SECONDS.sleep(2);
		blocked.cancel(true);
		Print.print("Checking in objects in " + list);
		for(Fat f : list) {
			pool.checkIn(f);
		}
		for(Fat f : list) {
			pool.checkIn(f);
		}
		exec.shutdown();
	}
}

class CheckoutTask<T> implements Runnable{
	private static int counter = 0;
	private final int id = counter++;
	private Pool<T> pool;
	public CheckoutTask(Pool<T> pool) {
		this.pool = pool;
	}
	public void run() {
		try {
			T item = pool.checkOut();
			Print.print(this + "checkout " + item);
			TimeUnit.SECONDS.sleep(1);
			Print.print(this + "checking in " + item);
			pool.checkIn(item);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public String toString() {
		return "CheckOutTask " + id + " ";
	}
}
